from flask import Flask, render_template, jsonify, Response
from flask_socketio import SocketIO, emit
import json
import socket
import threading
import time
import requests
import logging
from datetime import datetime

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

app = Flask(__name__)
app.config['SECRET_KEY'] = 'rk3588_video_test'
socketio = SocketIO(app, cors_allowed_origins="*", logger=False)

# 全局状态
video_data = {
    'connected': False,
    'protocol': 'Unknown',
    'status': 'offline',
    'codec': 'Unknown',
    'resolution': 'Unknown',
    'fps': 0,
    'bitrate': 'Unknown',
    'latency': 'Unknown',
    'last_update': None
}

# 激光雷达数据
lidar_data = {
    'connected': False,
    'latest_scan': None,
    'point_count': 0,
    'last_update': None,
    'device': '/dev/ttyACM0'
}

# TCP服务器状态
tcp_server_running = False
tcp_server_initialized = False


def start_tcp_data_server():
    """启动TCP数据接收服务器"""
    global tcp_server_running, tcp_server_initialized
    
    if tcp_server_running or tcp_server_initialized:
        return
    
    tcp_server_initialized = True
        
    def tcp_server_thread():
        global tcp_server_running
        
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        
        try:
            server_socket.bind(('0.0.0.0', 9000))
            server_socket.listen(5)
            tcp_server_running = True
            print("[成功] TCP数据服务器启动成功: 0.0.0.0:9000")
            
            while tcp_server_running:
                try:
                    client_socket, addr = server_socket.accept()
                    print(f"[连接] RK3588设备连接: {addr}")
                    
                    def handle_client():
                        video_data['connected'] = True
                        socketio.emit('connection_update', {'connected': True})
                        
                        try:
                            buffer = ""
                            while tcp_server_running:
                                data = client_socket.recv(4096)
                                if not data:
                                    break
                                
                                buffer += data.decode('utf-8')
                                
                                # 处理JSON消息
                                while '\n' in buffer:
                                    line, buffer = buffer.split('\n', 1)
                                    if line.strip():
                                        try:
                                            msg = json.loads(line.strip())
                                            
                                            if msg.get('type') == 'video':
                                                data_payload = msg.get('data', {})
                                                video_data.update(data_payload)
                                                video_data['last_update'] = datetime.now().strftime('%H:%M:%S')
                                                
                                                print(f"[视频] 数据更新: {data_payload.get('protocol', 'Unknown')} - {data_payload.get('codec', 'Unknown')}")
                                                socketio.emit('video_update', video_data)
                                                
                                            elif msg.get('type') == 'heartbeat':
                                                print("[心跳] 收到心跳包")
                                            
                                            elif msg.get('type') == 'lidar_data':
                                                # 处理激光雷达数据
                                                lidar_data.update({
                                                    'connected': True,
                                                    'latest_scan': {
                                                        'timestamp': msg.get('timestamp'),
                                                        'points': msg.get('points', []),
                                                        'point_count': msg.get('point_count', 0)
                                                    },
                                                    'point_count': msg.get('point_count', 0),
                                                    'last_update': datetime.now().strftime('%H:%M:%S'),
                                                    'device': msg.get('device', '/dev/ttyACM0')
                                                })
                                                
                                                # 广播激光雷达数据到前端
                                                socketio.emit('lidar_update', {
                                                    'points': msg.get('points', []),
                                                    'point_count': msg.get('point_count', 0),
                                                    'timestamp': msg.get('timestamp'),
                                                    'connected': True
                                                })
                                                
                                                print(f"[雷达] 点云数据: {msg.get('point_count', 0)} 个点")
                                                
                                        except json.JSONDecodeError:
                                            logger.warning(f"JSON解析失败: {line[:100]}")
                                        except Exception as e:
                                            logger.error(f"消息处理错误: {e}")
                                            
                        except Exception as e:
                            logger.error(f"客户端处理错误: {e}")
                        finally:
                            video_data['connected'] = False
                            video_data['status'] = 'offline'
                            client_socket.close()
                            socketio.emit('connection_update', {'connected': False})
                            print(f"[断开] RK3588设备断开: {addr}")
                    
                    # 为每个客户端创建处理线程
                    client_thread = threading.Thread(target=handle_client, daemon=True)
                    client_thread.start()
                    
                except Exception as e:
                    if tcp_server_running:
                        logger.error(f"接受连接失败: {e}")
                        
        except Exception as e:
            logger.error(f"TCP服务器启动失败: {e}")
        finally:
            tcp_server_running = False
            if server_socket:
                server_socket.close()
    
    # 在后台线程中启动TCP服务器
    tcp_thread = threading.Thread(target=tcp_server_thread, daemon=True)
    tcp_thread.start()
    
    # 等待服务器启动
    time.sleep(0.5)

# Flask应用初始化 - 兼容新版本Flask
@app.before_request
def initialize_app():
    """Flask应用初始化 - 只执行一次"""
    global tcp_server_initialized
    if not tcp_server_initialized:
        print("[启动] 初始化RK3588视频流测试系统...")
        start_tcp_data_server()

@app.route('/')
def index():
    """主页"""
    return render_template('index.html')

@app.route('/api/status')
def api_status():
    """获取系统状态API"""
    return jsonify({
        'video_data': video_data,
        'lidar_data': lidar_data,
        'tcp_server_running': tcp_server_running,
        'server_time': datetime.now().isoformat()
    })

@app.route('/api/lidar')
def api_lidar():
    """获取激光雷达数据API"""
    return jsonify(lidar_data)

@app.route('/video_proxy')
def video_proxy():
    """MJPEG视频流代理 - 直接转发原始数据"""
    def generate_video():
        max_retries = 3
        retry_count = 0
        
        while retry_count < max_retries:
            try:
                # TCP连接到RK3588
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.settimeout(10)
                sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
                sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                
                sock.connect(('192.168.233.110', 8080))
                logger.info("[视频] TCP连接成功，开始转发MJPEG数据")
                
                # 直接转发原始数据
                while True:
                    try:
                        data = sock.recv(16384)  # 16KB块
                        if not data:
                            logger.info("[视频] 数据流结束")
                            break
                        
                        yield data
                        
                    except socket.timeout:
                        logger.debug("[视频] 接收超时")
                        continue
                    except Exception as e:
                        logger.error(f"[视频] 数据接收错误: {e}")
                        break
                
                sock.close()
                break
                    
            except Exception as e:
                logger.warning(f"[视频] 连接错误: {e} (重试 {retry_count + 1}/{max_retries})")
                retry_count += 1
                if retry_count < max_retries:
                    time.sleep(2)
        
        # 连接失败时输出错误信息
        if retry_count >= max_retries:
            logger.error("[视频] 所有重试失败，视频流不可用")
    
    return Response(
        generate_video(),
        mimetype='multipart/x-mixed-replace; boundary=frame',
        headers={
            'Cache-Control': 'no-cache, no-store, must-revalidate',
            'Pragma': 'no-cache',
            'Expires': '0',
            'Access-Control-Allow-Origin': '*'
        }
    )

# WebSocket事件处理
@socketio.on('connect')
def handle_connect():
    """WebSocket客户端连接"""
    logger.info("Web客户端连接")
    emit('video_update', video_data)
    emit('connection_update', {'connected': video_data['connected']})
    emit('lidar_update', {
        'points': lidar_data.get('latest_scan', {}).get('points', []) if lidar_data.get('latest_scan') else [],
        'point_count': lidar_data.get('point_count', 0),
        'connected': lidar_data.get('connected', False)
    })

@socketio.on('request_status')
def handle_request_status():
    """请求状态更新"""
    emit('video_update', video_data)
    emit('connection_update', {'connected': video_data['connected']})

@socketio.on('disconnect')
def handle_disconnect():
    """WebSocket客户端断开"""
    logger.info("Web客户端断开")

# 无论如何都确保监听所有接口
import os
if os.environ.get('FLASK_RUN_HOST') is None:
    os.environ['FLASK_RUN_HOST'] = '0.0.0.0'
if os.environ.get('FLASK_RUN_PORT') is None:
    os.environ['FLASK_RUN_PORT'] = '5000'

# 如果直接运行python app.py时的配置
if __name__ == '__main__':
    print("[直接运行] 启动模式")
    start_tcp_data_server()
    print("[Web] 界面地址: http://192.168.233.187:5000")
    socketio.run(app, debug=False, host='0.0.0.0', port=5000)